package com.shenhua.kunpeng.mybatis;

import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.shenhua.kunpeng.config.TenantTableFilterConfig;
import com.shenhua.kunpeng.db.DbConfig;
import com.shenhua.kunpeng.handler.MyMetaObjectHandler;
import com.shenhua.kunpeng.utils.TenantIdContextHolder;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

/**
 * mybatisplus 配置类
 */
@Configuration
@Import({DbConfig.class, TenantTableFilterConfig.class})
public class MybatisPlusConfig {
  @Autowired private TenantTableFilterConfig tenantTableFilterConfig;

  @Bean("sqlSessionFactory")
  public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource)
      throws Exception {
    MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
    sqlSessionFactory.setDataSource(dataSource);
    // 开启XML
    sqlSessionFactory.setMapperLocations(
        new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*Mapper.xml"));

    MybatisConfiguration configuration = new MybatisConfiguration();

    // 开启XML
    configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
    configuration.setJdbcTypeForNull(JdbcType.NULL);
    configuration.setMapUnderscoreToCamelCase(true);
    configuration.setCacheEnabled(false);
    sqlSessionFactory.setConfiguration(configuration);
    sqlSessionFactory.setPlugins(mybatisPlusInterceptor());

    GlobalConfig globalConfig = new GlobalConfig();
    globalConfig.setMetaObjectHandler(myMetaObjectHandler());
    sqlSessionFactory.setGlobalConfig(globalConfig);

    return sqlSessionFactory.getObject();
  }

  @Bean
  public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(getTenantLineInnerInterceptor());
    // 如果用了分页插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor
    // 用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
  }

  @Bean
  public ConfigurationCustomizer configurationCustomizer() {
    return configuration -> configuration.setUseDeprecatedExecutor(false);
  }

  @Bean
  public MyMetaObjectHandler myMetaObjectHandler() {
    return new MyMetaObjectHandler();
  }


  private TenantLineInnerInterceptor getTenantLineInnerInterceptor() {
    return new TenantLineInnerInterceptor(
            new TenantLineHandler() {
              @Override
              public Expression getTenantId() {
                Long tenantId = TenantIdContextHolder.get();
                if (tenantId == null) {
                  throw new RuntimeException("缺少租户 ID");
                }
                return new LongValue(tenantId);
              }

              /**
               * 根据表名判断是否忽略拼接多租户条件
               *
               * <p>默认都要进行解析并拼接多租户条件
               *
               * @param tableName 表名
               * @return 是否忽略, true:表示忽略，false:需要解析并拼接多租户条件
               */
              @Override
              public boolean ignoreTable(String tableName) {
                return tenantTableFilterConfig.getFilters().contains(tableName);
              }
            });
  }

}
